/*
 * =====================================================================================
 *
 *       Filename:  cl_poll_poller.cxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  04/08/2011 03:24:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ken Chen (Ken), chen_kenz@emc.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <cassert>
#include "cl_poll_poller.hxx"

namespace neo
{
using namespace std;

CLPollPoller::~CLPollPoller() 
{
}

bool CLPollPoller::doPoll(long millisecs, CLChannelList& chs) 
{
  if(m_events.empty())
  {
    return true;
  }

  int readyEvents = ::poll(&m_events[0], m_events.size(), millisecs);
  if(readyEvents > 0)
  {
    fillReadyChannels(readyEvents, chs);
    return true;
  }
  else if(readyEvents == 0)
  {
    // timeout
    return true;
  }
  else
  {
    return false;
  }
}

bool CLPollPoller::doAdd(CLChannel* ch) 
{
  assert(ch != NULL);
  ChannelMap::const_iterator itr = m_channels.find(ch->fd());
	if(itr != m_channels.end())
	{
	  return false;
	}

  m_channels.insert(make_pair(ch->fd(), ch));
  struct pollfd pfd;
  pfd.fd = ch->fd();
  pfd.events = ch->events();
  pfd.revents = 0;
  m_events.push_back(pfd);
	return true;
}

bool CLPollPoller::doRemove(CLChannel* ch) 
{
  ChannelMap::iterator itr = m_channels.find(ch->fd());
	if(itr == m_channels.end())
	{
	  return false;
	}
  m_channels.erase(itr);

  EventVector::iterator evtItr;
  assert(findEventfd(ch->fd(), evtItr));
  m_events.erase(evtItr);
	return true;
}

bool CLPollPoller::doModify(CLChannel* ch) 
{
  ChannelMap::const_iterator itr = m_channels.find(ch->fd());
	if(itr == m_channels.end())
	{
	  return false;
	}

  EventVector::iterator evtItr;
  assert(findEventfd(ch->fd(), evtItr));
  (*evtItr).events = ch->events();
	return true;
}

bool CLPollPoller::findEventfd(int pfd, EventVector::iterator& itr)
{
  EventVector::iterator evtItr = m_events.begin();
  EventVector::iterator evtItrEnd = m_events.end();
  for(; evtItr != evtItrEnd; ++evtItr)
  {
    if((*evtItr).fd == pfd)
    {
      itr = evtItr;
      return true;
    }
  }
  
  return false;
}

void CLPollPoller::fillReadyChannels(int readyEvents, CLChannelList& chs) 
{
  EventVector::iterator evtItr = m_events.begin();
  EventVector::iterator evtItrEnd = m_events.end();
  for(; evtItr != evtItrEnd; ++evtItr)
  {
    if((*evtItr).revents != 0)
    {
      // Has events, find the corresponding channel 
      ChannelMap::const_iterator itr = m_channels.find((*evtItr).fd);
      assert(itr != m_channels.end());
      chs.push_back((*itr).second);
      (*itr).second->setReadyEvents((*evtItr).revents);
      (*evtItr).revents = 0;
    }
  }
  assert(static_cast<size_t>(readyEvents) == chs.size());
}

} // neo
